/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.uca.dss.curso2011.grupo5;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.uca.dss.curso2011.grupo5.interfazExtendido.InformacionTrayecto;
import org.uca.dss.curso2011.grupo5.interfazExtendido.Itinerario;

/**
 * Clase que gestiona los trayectos posibles para hacer un determinado viaje.
 * @author Diego
 */
public class Transbordo
{
    private List<Trayecto> ltrayectos;

    /**
     *
     * @param ltrayectos lista de trayectos disponibles en la agencia.
     */
    public Transbordo(List<Trayecto> ltrayectos) throws IllegalArgumentException
    {
        // Compruebo argumentos
        Args.comprobarNulo(ltrayectos);

        this.ltrayectos = ltrayectos;
    }

    /**
     * Devuelve la lista de itinerarios que salen desde ciudadOrigen y llegan a ciudadDestino en la fecha indicada
     * @param ciudadOrigen ciudad desde la que se parte
     * @param ciudadDestino ciudad a la que se quiere llegar
     * @param fecha fecha en la que se realiza el viaje
     * @return la lista de itinerarios que salen desde ciudadOrigen y llegan a ciudadDestino en la fecha indicada
     */
    public List<Itinerario> obtenerItinerarios(String ciudadOrigen, String ciudadDestino, LocalDate fecha) throws IllegalArgumentException, RuntimeException
    {
        // Comrpuebo argumentos
        Args.comprobarCadena(ciudadOrigen);
        Args.comprobarCadena(ciudadDestino);
        Args.comprobarNulo(fecha);

        // Calculos los itinerarios directo y con transbordo
        List<Itinerario> itinerarios = obtenerTransbordos(ciudadOrigen,ciudadDestino,fecha);

        itinerarios.addAll(obtenerDirectos(ciudadOrigen,ciudadDestino,fecha));

        return itinerarios;
    }

    /**
     * Devuelve la lista de itinerarios que salen desde ciudadOrigen y llegan a
     * ciudadDestino en la fecha indicada con un transbordo de por medio
     * @param ciudadOrigen ciudad desde la que se parte
     * @param ciudadDestino ciudad a la que se quiere llegar
     * @param fecha fecha en la que se realiza el viaje
     * @return la lista de itinerarios que salen desde ciudadOrigen y llegan a
     * ciudadDestino en la fecha indicada con un transbordo de por medio
     */
    private List<Itinerario> obtenerTransbordos(String ciudadOrigen, String ciudadDestino, LocalDate fecha) throws IllegalArgumentException, RuntimeException
    {
        // Compruebo argumentos
        Args.comprobarCadena(ciudadOrigen);
        Args.comprobarCadena(ciudadDestino);
        Args.comprobarNulo(fecha);

        List<Trayecto> origenes = new ArrayList<Trayecto>();
        List<Trayecto> destinos = new ArrayList<Trayecto>();
        List<Itinerario> itinerarios = new ArrayList<Itinerario>();
        GestionReservas gestionReservas = new GestionReservas(ltrayectos);

        // Recorremos todos los trayectos de la agencia y nos quedamos con los
        // que cumplen las condiciones de origen y de destino.
        for(Trayecto t : ltrayectos)
        {
            if(t.getCiudadOrigen().equals(ciudadOrigen))
            {
                origenes.add(t);
            }
            else if(t.getCiudadDestino().equals(ciudadDestino))
            {
                destinos.add(t);
            }
        }

        // Recorremos los trayectos origen y para cada trayecto destino,
        // comprobamos si hay un transbordo (ciudadDestinoOrigen == ciudadSalidaDestino)
        for(Trayecto o : origenes)
        {
            for(Trayecto d : destinos)
            {
                if(o.getCiudadDestino().equals(d.getCiudadOrigen()))
                {
                    Iterator<HorarioTren> ihorigenes = o.getHorarios();

                    while(ihorigenes.hasNext())
                    {
                        HorarioTren ho = ihorigenes.next();
                        InformacionTrayecto iTo = new InformacionTrayecto(o.getCiudadOrigen(),o.getCiudadDestino(),
                        new LocalTime(ho.getHoraSalida()),new LocalTime(ho.getHoraLlegada()),
                        o.calcularPrecioTrayecto(new LocalTime(ho.getHoraSalida())));

                        // Comprobar reservas realizadas
                        if((ho.getNumAsientos() - gestionReservas.reservasRealizadas(iTo,fecha)) > 0)
                        {
                            Iterator<HorarioTren> ihdestinos = d.getHorarios();

                            while(ihdestinos.hasNext())
                            {
                                HorarioTren hd = ihdestinos.next();
                                InformacionTrayecto iTd = new InformacionTrayecto(d.getCiudadOrigen(),d.getCiudadDestino(),
                                new LocalTime(hd.getHoraSalida()),new LocalTime(hd.getHoraLlegada()),
                                d.calcularPrecioTrayecto(new LocalTime(hd.getHoraSalida())));

                                // Comprobar reservas realizadas
                                if((hd.getNumAsientos() - gestionReservas.reservasRealizadas(iTd,fecha)) > 0)
                                {
                                    LocalTime horaLlegada = new LocalTime(ho.getHoraLlegada());
                                    LocalTime horaSalida = new LocalTime(hd.getHoraSalida());

                                    // Por último comprobamos si hay 10 minutos como mínimo entre uno y otro
                                    if(horaSalida.minusMinutes(10).isAfter(horaLlegada) ||
                                       horaSalida.minusMinutes(10).isEqual(horaLlegada))
                                    {
                                        List<InformacionTrayecto> itinerario = new ArrayList<InformacionTrayecto>();
                                        itinerario.add(iTo);
                                        itinerario.add(iTd);

                                        itinerarios.add(new ImplementacionItinerario(itinerario));
                                    }
                                }
                                else
                                {
                                    throw new RuntimeException("Transbordo: No existen asientos libre en el transbordo.");
                                }
                            }
                        }
                        else
                        {
                            throw new RuntimeException("Transbordo: No existen asientos libre en el transbordo.");
                        }
                    }
                }
            }
        }

        return itinerarios;
    }

    /**
     * Devuelve la lista de itinerarios que salen desde ciudadOrigen y llegan a
     * ciudadDestino en la fecha indicada de forma directa
     * @param ciudadOrigen ciudad desde la que se parte
     * @param ciudadDestino ciudad a la que se quiere llegar
     * @param fecha fecha en la que se realiza el viaje
     * @return la lista de itinerarios que salen desde ciudadOrigen y llegan a
     * ciudadDestino en la fecha indicada de forma directa
     * @throws IllegalArgumentException
     * @throws RuntimeException
     */
    private List<Itinerario> obtenerDirectos(String ciudadOrigen, String ciudadDestino, LocalDate fecha) throws IllegalArgumentException, RuntimeException
    {
        // Compruebo argumentos
        Args.comprobarCadena(ciudadOrigen);
        Args.comprobarCadena(ciudadDestino);
        Args.comprobarNulo(fecha);


       List<Itinerario> itinerarios = new ArrayList<Itinerario>();
       GestionReservas gestionReservas = new GestionReservas(ltrayectos);

       try
       {
           Viaje v = new Viaje(fecha, ciudadOrigen, ciudadDestino, ltrayectos);
           Iterator<Trayecto> iteradorTrayecto = v.getTrayectos();
           
           while(iteradorTrayecto.hasNext())
           {
               Trayecto trayecto = iteradorTrayecto.next();

               Iterator<HorarioTren> ihorarios = trayecto.getHorarios();

               while(ihorarios.hasNext())
               {
                   HorarioTren h = ihorarios.next();

                   InformacionTrayecto itrayecto = new InformacionTrayecto(ciudadOrigen, ciudadDestino,
                        new LocalTime(h.getHoraSalida()), new LocalTime(h.getHoraLlegada()),
                        trayecto.calcularPrecioTrayecto(new LocalTime(h.getHoraSalida())));

                   if((h.getNumAsientos() - gestionReservas.reservasRealizadas(itrayecto,fecha)) > 0)
                   {
                        List<InformacionTrayecto> itinerario = new ArrayList<InformacionTrayecto>();

                        itinerario.add(itrayecto);
                        itinerarios.add(new ImplementacionItinerario(itinerario));
                   }
                   else
                   {
                        throw new RuntimeException("Transbordo: No existen asientos libre en trayecto directo.");
                   }
               }
           }

           return itinerarios;
       }
       catch (RuntimeException e)
       {
          return itinerarios;
       }     
    }
}
